// import { register, lib } from "@aotoo/react-cell";
import { register, lib } from "./cell";

function onFileChangeClick(param, cb, type) {
  if (typeof param === "function") {
    cb = param;
    param = null;
  }
  const hasSelected = this.hasSelected
  return function (e) {
    // 使用bloburl显示图片(二进制)
    const blobs = [];
    const files = e.target.files;
    const inputId = e.target.id
    for (let ii = 0; ii < files.length; ii++) {
      let file = files[ii];
      let url = URL.createObjectURL(file);
      blobs.push(url);
      if (type === "img" || type === "mov") {
        if (type === "img") {
          let image = new Image(); //新建一个img标签
          image.src = url;
          image.onload = function () {
            file.mediaInfo = {
              name: file.name,
              width: image.width,
              height: image.height,
              size: file.size,
              type: file.type
            };
            if (ii === files.length - 1) {
              hasSelected[inputId] = {urls: blobs, files: files}
              if (typeof cb === "function") {
                cb(blobs, files);
              }
            }
          };
        }

        if (type === "mov") {
          const video = document.createElement("video");
          video.preload = "metadata";
          video.src = url;
          video.onloadedmetadata = function () {
            file.mediaInfo = {
              name: file.name,
              width: video.videoWidth,
              height: video.videoHeight,
              size: file.size,
              duration: video.duration,
              type: file.type
            };
            if (ii === files.length - 1) {
              hasSelected[inputId] = {urls: blobs, files: files}
              if (typeof cb === "function") {
                cb(blobs, files);
              }
            }
          };
        }
      } else {
        file.mediaInfo = {
          name: file.name,
          size: file.size,
          type: file.type
        };
      }
    }

    if (["img", "mov"].indexOf(type) === -1) {
      hasSelected[inputId] = {urls: blobs, files: files}
      if (typeof cb === "function") {
        cb(blobs, files);
      }
    }
  };
}

function onDeleteMediaClick(id, placeholderId, placeholder, removePreview) {
  return function (e) {
    let removeStat = true

    if (typeof removePreview === "function") {
      removeStat = removePreview(e)
    }

    if (removeStat) {
      const ele = document.getElementById(id);
      ele.src = "";
      ele.style.display = "none";
      if (placeholder) {
        const holder = document.getElementById(placeholderId);
        if (holder) {
          holder.style.display = "block";
        }
      }
      e.target.style.display = "none";
    }
  };
}

function Uploader(props) {
  let $props = { ...props };
  let elementStore = $props.store; 
  delete $props.store;
  
  const registeroptions = $props.registeroptions || {};
  delete $props.registeroptions;

  const template = $props.template; 
  delete $props.template;

  const server = $props.server; 
  delete $props.server;
  
  const $id = $props.id;
  const $value = $props.value;
  let   targetValue = [{ src: $value }]
  let   resetTargetValue = (urls=[], files=[]) => {
    urls = [].concat(urls)
    files = [].concat(files)

    if ($value) {
      targetValue = [{ src: $value }]
    }

    urls.forEach((url, ii)=>{
      let item = {src: url}
      if (files[ii]) {
        item.file = files[ii]
      }
      targetValue.push(item)
    })
    return targetValue
  }
  elementStore.getValue = function(){
    return targetValue
  }

  let   _selected = $props.selected || registeroptions.selected || elementStore.selected
  let   _uploaded = $props.uploaded || registeroptions.uploaded || elementStore.uploaded
  let   _upload = $props.upload || registeroptions.upload || elementStore.upload
  
  let resultContext = {
    hasSelected: {}
  }

  const context = {
    previewIn(id, blob, placeholderId) {
      if (typeof id === "string") {
        const media = document.getElementById(id);
        if (media) {
          if (typeof placeholderId === "string") {
            let holder = document.getElementById(placeholderId);
            if (holder) {
              holder.style.display = "none";
            }
          }
          media.src = blob;
          media.style.display = "block";
          media.onload = function (e) {
            URL.revokeObjectURL(this.src);
          };
        }
      }
    },
    // 创建上传按钮
    createButton(param, opts = {}, cb) {
      if (typeof opts === "function") {
        cb = opts;
        opts = {};
      }

      if (typeof param === "string") {
        param = { title: param };
      }

      opts.id = opts.id || lib.uniqueId(('uploader-button-'+$id))
      const className = (opts.className || ''); delete opts.className
      // resultContext.hasSelected[opts.id] = null

      let targetButton = null;
      if (React.isValidElement(param)) {
        let btn = React.cloneElement(param, {className})
        targetButton = (
          <div className={"uploader-cell "+ className}>
            {btn}
            <input 
              className="uploader-input" 
              type="file" 
              onChange={onFileChangeClick.call(resultContext, {}, cb)} {...opts} 
            />
          </div>
        );
      } else {
        if (typeof param === "object" && !Array.isArray(param)) {
          targetButton = (
            <div className={"uploader-cell "+ className}>
              <div className={"button-normal "+className}>{param.title}</div>
              <input className="uploader-input" type="file" onChange={onFileChangeClick.call(resultContext, {}, cb)} {...opts} />
            </div>
          );
        }
      }
      return targetButton;
    },

    createImgButton(id, opts = {}, cb) {
      const that = this;
      id = id || lib.uniqueId('uploader-img-button-')
      if (typeof id === "string") {
        if (typeof opts === "string") {
          opts = { src: opts };
        }

        if (typeof opts === "function") {
          cb = opts;
          opts = {};
        }

        opts.id = opts.id || lib.uniqueId(('uploader-img-input-'+$id))
        // resultContext.hasSelected[opts.id] = null

        const preview = opts.preview; // 鼠标划过时预览
        delete opts.preview;

        const className = opts.className||''; 
        delete opts.className;
        
        let   src = opts.src || "empty"; 
        delete opts.src;
        
        const key = opts.key || null; 
        delete opts.key;

        const removePreview = opts.removePreview || null
        delete opts.removePreview

        let targetButton = null;
        opts.multiple = false;
        opts.accept = opts.accept || ".jpg, .jpeg, .png, .gif";

        let display = null;
        let placeholder = null;
        let placeholderId = id + "-placeholder";
        let tmp = opts.placeholder;
        tmp = React.isValidElement(tmp) ? (
          tmp
        ) : lib.isString(tmp) ? (
            <i className={tmp} />
          ) : lib.isObject(tmp) ? (
              <i className={tmp.className||'uploader-placeholder'} />
            ) : <img alt="" src="//via.placeholder.com/160x90?text=IMAGE+HOLDER" />

        placeholder = React.cloneElement(tmp, { id: placeholderId });
        if (src === "empty") {
          src = "";
          display = { style: { display: "none" } };
        } else {
          placeholder = React.cloneElement(placeholder, {style: {display: "none"}});
        }

        targetButton = (
          <div className={"uploader-cell "+ className}>
            <img src={(src||'')} alt="" id={id} className={"uploader-img-preview"} {...display} />
            {placeholder}
            <input type="file" data-mediaid={id}
              className="uploader-input"
              onChange={onFileChangeClick.call(resultContext, 
                {},
                function (blobs, files) {
                  that.previewIn(id, blobs[0], placeholderId);
                  let deleteButtons = document.querySelectorAll('.delete-preview-img')
                  deleteButtons.forEach(btn=>{
                    let mediaid = btn.getAttribute('data-mediaid')
                    if (mediaid === id) {
                      btn.style.display = 'block'
                    }
                  })
                  if (typeof cb === "function") cb(blobs, files);
                },
                "img"
              )}
              {...opts}
            />
            {src ? <i className="delete-preview-img" data-mediaid={id} onClick={onDeleteMediaClick(id, placeholderId, placeholder, removePreview)} ></i> : null}
          </div>
        );
        if (key) {
          targetButton = React.cloneElement(targetButton, { key: key });
        }
        return targetButton;
      }
    },
    createMovieButton(id, opts = {}, cb) {
      const that = this;
      const videoAttributs = [
        "autoplay",
        "controls",
        "height",
        "loop",
        "muted",
        "poster",
        "preload",
        "src",
        "width"
      ];
      id = id || lib.uniqueId('uploader-movie-button-')
      if (typeof id === "string") {
        if (typeof opts === "string") {
          opts = { src: opts };
        }

        if (typeof opts === "function") {
          cb = opts;
          opts = {};
        }

        opts.id = opts.id || lib.uniqueId(('uploader-movie-input-'+$id))
        // resultContext.hasSelected[opts.id] = null

        let acceptAttributs = {};
        if (opts.mediaOption) {
          acceptAttributs = opts.mediaOption;
          delete opts.mediaOption;
        } else {
          Object.keys(opts).forEach((ky) => {
            if (videoAttributs.indexOf(ky) > -1) {
              const val = opts[ky];
              acceptAttributs[ky] = val;
              delete opts[ky];
            }
          });
        }

        acceptAttributs.width = acceptAttributs.width || 320;
        acceptAttributs.height = acceptAttributs.height || 180;

        let preview = opts.preview; // 鼠标划过时预览
        delete opts.preview;

        const className = opts.className||''; 
        delete opts.className;

        let src = opts.src || "empty";
        delete opts.src;
        
        let key = opts.key || null;
        delete opts.key;

        let removePreview = opts.removePreview || null
        delete opts.removePreview;
        
        let targetButton = null;
        opts.multiple = false;
        opts.accept = opts.accept || ".mp4, .flv";

        let display = null;
        let placeholder = null;
        let placeholderId = id + "-placeholder";
        let tmp = opts.placeholder
        tmp = React.isValidElement(tmp) ? (
          tmp
        ) : lib.isString(tmp) ? (
            <i className={tmp} />
          ) : lib.isObject(tmp) ? (
              <i className={tmp.className||'uploader-placeholder'} />
            ) : <img alt="" src="//via.placeholder.com/160x90?text=MOVIE+HOLDER" />
        placeholder = React.cloneElement(tmp, { id: placeholderId });
        if (src === "empty") {
          src = "";
          display = { style: { display: "none" } };
        } else {
          placeholder = React.cloneElement(placeholder, {style: {display: "none"}});
        }

        targetButton = (
          <div className={"uploader-cell "+ className}>
            <video src={(src||'')} id={id} controls="controls" {...acceptAttributs} className={"uploader-mov-preview"} {...display} >
              您的浏览器不支持 video 标签。
            </video>
            {placeholder}
            <input type="file" data-mediaid={id}
              className="uploader-input"
              onChange={onFileChangeClick.call(resultContext, 
                {},
                function (blobs, files) {
                  that.previewIn(id, blobs[0], placeholderId);
                  if (typeof cb === "function") cb(blobs, files);
                },
                "mov"
              )}
              {...opts}
            />
            <i className="delete-preview-img" data-mediaid={id} onClick={onDeleteMediaClick(id, placeholderId, placeholder, removePreview)} ></i>
          </div>
        );
        if (key) {
          targetButton = React.cloneElement(targetButton, { key: key });
        }
        return targetButton;
      }
    },
    createCrackButton() {},
    slice(file, opts) {
      let start = opts.start || 0;
      let end = 0;
      let index = opts.index || 0;
      let filesize = file.size;
      let filename = file.name;
      let bytesPerPiece = opts.block || 1024 * 1024;
      let uploadId = opts.uploadId || "upload-stream-slice-" + filename;
      let allFormData = [];

      //计算文件切片总数
      let totalPieces = Math.ceil(filesize / bytesPerPiece);
      while (start < filesize) {
        end = start + bytesPerPiece;
        if (end > filesize) {
          end = filesize;
        } // 匹配最后一个分片的情况

        let chunk = file.slice(start, end); //切割文件
        let percentComplete = Math.round((start * 100) / filesize);
        let formData = new FormData();

        formData.append("fileName", file.name); //文件名
        formData.append("total", totalPieces); //总块数
        formData.append("index", index); //当前上传的块下标
        formData.append("uploadId", uploadId); //上传编号
        formData.append("__percent", percentComplete); //上传编号
        formData.append("file", chunk);
        allFormData.push(formData); // 缓存所有需要上传的分片
      }
      return allFormData;
    },
    upload(url, file, opts = {}) {
      url = url || server
      const hasSelected = resultContext.hasSelected
      if (!url) {
        throw new Error('需要指定上传地址')
      }

      if (typeof _upload === 'function') {
        _upload.call(context, url, file)
        return
      }
      
      function defaultUploader(ff){
        try {
          if (!( ff instanceof FormData)) {
            let oldff = ff
            if (ff.length) ff = ff[0];
            const formData = new FormData()
            formData.append("name", ff.name); //文件名
            formData.append("type", ff.type); //总块数
            formData.append("size", ff.size); //当前上传的块下标
            formData.append("lastModifiedDate", ff.lastModifiedDate); //当前上传的块下标
            formData.append("file", ff);
            ff = formData;
          }

          return fetch(url, {
            method: "POST", // or 'PUT'
            body: ff, // formData 类型
            // headers: new Headers(opts.headers || {})
          })
          .then((res) => {
            let jsonData = res.json();
            if (ff.__percent) {
              jsonData.percent = ff.__percent;
            }
            return jsonData;
          })
          .catch((error) => console.error("Error:", error));
        } catch (error) {
          return console.error("Error:", error);
        }
      }

      if (file) {
        return defaultUploader(file).then(res=>{
          if (typeof _uploaded === 'function') {
            _uploaded(res)
          }
        })
      } else {
        let len = Object.keys(hasSelected).length
        if (len) {
          const allpromise = []
          Object.keys(hasSelected).forEach(inputid=>{
            let val = hasSelected[inputid]
            let thefiles = val.files
            allpromise.push(defaultUploader(thefiles))
          })
          return Promise.all(allpromise).then(res=>{
            if (typeof _uploaded === 'function') {
              _uploaded(res)
            }
          })
          .catch((error) => console.error("Error:", error));
        } else {
          console.warn('还没有上传任何文件');
        }
      }
    }
  };

  // elementStore.upload = context.upload
  elementStore = Object.assign(elementStore, context)
  let extendTemplate = registeroptions.template || {}

  if (typeof template === "function") {
    return template.call(elementStore, $props);
  } else {
    if (template && lib.isPlainObject(template)) {
      let type = template.type  // button img movie
      let id = template.id
      let src = template.src
      let placeholder = template.placeholder
      let className = template.className
      if (extendTemplate[type]) {
        if (typeof extendTemplate[type] === 'function') {
          return extendTemplate[type].call(elementStore, $props);
        }
      }

      if (type === 'button' || type === 'btn') {
        let title = template.title || '上传'
        let multiple = template.multiple || false
        return context.createButton(title, {title, multiple, className}, function(urls, files){
          resetTargetValue(urls, files)
          if (typeof _selected === 'function') {
            _selected.call(elementStore, urls, files)
          }
        })
      }
      if (type === 'img') {
        src = src || $value
        return context.createImgButton(id, {src, placeholder, className}, function(urls, files){
          resetTargetValue(urls, files)
          if (typeof _selected === 'function') {
            _selected.call(elementStore, urls, files)
          }
        })
      }
      if (type === 'mov' || type === 'movie') {
        src = src || $value
        return context.createMovieButton(id, {src, placeholder, className}, function(urls, files){
          resetTargetValue(urls, files)
          if (typeof _selected === 'function') {
            _selected.call(elementStore, urls, files)
          }
        })
      }
    }
    return context.createButton('上传', {multiple: false}, function(urls, files){
      resetTargetValue(urls, files)
      if (typeof _selected === 'function') {
        _selected.call(elementStore, urls, files)
      }
    })
  }
}

register("Uploader", ["uploader"], Uploader);